
/*    This file is part of the managarm operating system.
 *   Copyright (C) 2007, 2008, 2009  Alexander van der Grinten
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

package org.managarm.jmanacclib.frontend.korona;

//import managarm virtual architecture classes
import org.managarm.jmanacclib.core.CclibUnit;
import org.managarm.jmanacclib.core.CclibException;
import org.managarm.jmanavalib.core.VaDatatype;
import org.managarm.jmanavalib.core.VaLiteral;

import ast.AstConstInteger;
import ast.AstRoot;
import ast.AstSpace;
import ast.AstClass;
import ast.AstTerm;

public final class KorUtils {
	public static class UnresolvedException extends Throwable {
		private static final long serialVersionUID = 2372838230409265901L;
	}
	
	private KorUtils() { }
	
	/* returns the primitive id of a primitive type or -1 if ident is not a primitive type */
	public final static VaDatatype primResolve(final String ident) throws CclibException {
		if(ident.equals("byte")) {
			return new VaDatatype.DtPrimitive(VaDatatype.DtPrimitive.PRIM_BYTE);
		}else if(ident.equals("ubyte")) {
			return new VaDatatype.DtPrimitive(VaDatatype.DtPrimitive.PRIM_UBYTE);
		}else if(ident.equals("short")) {
			return new VaDatatype.DtPrimitive(VaDatatype.DtPrimitive.PRIM_SHORT);
		}else if(ident.equals("ushort")) {
			return new VaDatatype.DtPrimitive(VaDatatype.DtPrimitive.PRIM_USHORT);
		}else if(ident.equals("int")) {
			return new VaDatatype.DtPrimitive(VaDatatype.DtPrimitive.PRIM_INT);
		}else if(ident.equals("uint")) {
			return new VaDatatype.DtPrimitive(VaDatatype.DtPrimitive.PRIM_UINT);
		}else if(ident.equals("long")) {
			return new VaDatatype.DtPrimitive(VaDatatype.DtPrimitive.PRIM_LONG);
		}else if(ident.equals("ulong")) {
			return new VaDatatype.DtPrimitive(VaDatatype.DtPrimitive.PRIM_ULONG);
		}else if(ident.equals("char")) {
			return new VaDatatype.DtPrimitive(VaDatatype.DtPrimitive.PRIM_CHAR);
		}else if(ident.equals("boolean")) {
			return new VaDatatype.DtPrimitive(VaDatatype.DtPrimitive.PRIM_BOOLEAN);
		}else if(ident.equals("void")) {
			return new VaDatatype.DtPrimitive(VaDatatype.DtPrimitive.PRIM_NULL);
		}
		
		// ident is not a primitive type
		return null;
	}
	
	public final static AstSpace spaceResolve(final KorAstNode node,
			final AstClass cnt, final AstRoot root) throws CclibException {
		if(node instanceof AstTerm) {
			// start with the first term
			AstTerm term = (AstTerm)node;
			
			// start at the root
			AstSpace space = root;
			
			while(term != null) {
				// resolve the space
				space = (AstSpace)space.getSpaceEntry(term.getIdentifier());
				
				// go to the next term
				term = (AstTerm)term.getChild();
			}
			
			return space;
		}
		
		throw new CclibException("Compile error: Could not resolve the node "
				+ node.getClass().getSimpleName(),
				(CclibUnit)cnt.getAttribute("unit"), node.line());
	}
	
	public static boolean isLiteral(KorAstNode node) {
		if(node instanceof AstConstInteger)
			return true;
		return false;
	}
	
	public static VaLiteral buildLiteral(KorAstNode node) throws CclibException {
		if(node instanceof AstConstInteger){
			final AstConstInteger literal = (AstConstInteger) node;
			final long value = literal.getValue();
			// determine the integer type/length
			if(value < (1L << 31)){
				return new VaLiteral.LitUInt(value);
			}else if(value < (1L << 32)){
				return new VaLiteral.LitUInt(value);
			}else if(value < (1L << 63)){
				throw new CclibException("Internal error: " +
						"Could not encode literal node");
			}else{
				throw new CclibException("Internal error: " +
						"Could not encode literal node");
			}
		}else{
			throw new CclibException("Internal error: Unknown literal node");
		}
	}
}
